import React, { FC, ReactElement, useCallback, memo } from "react";
import styled, { css } from "styled-components";
import { DeleteIcon } from "../BUI";
import { Todo } from "./types";

interface DragProps {
  drag: boolean;
  setDrag: React.Dispatch<React.SetStateAction<boolean>>;
}

interface TodoComponentProps extends DragProps {
  todo: Todo;
  leftIcon?: ReactElement;
  handleDelete: (id: string) => () => void;
  done?: boolean;
  handleDone: (id: string) => () => void;
  handleTodo: (id: string) => () => void;
}

enum DragConstant {
  DRAG_ELEMENT_ID = "DRAG_ELEMENT_ID",
  DRAG_ELEMENT_STATUS = "DRAG_ELEMENT_STATUS",
  DRAG_HEIGHT = "DRAG_HEIGHT",
  DATA_PROPERTY = "data-position",
  POSITION_TOP = "top",
  POSITION_BOTTOM = "bottom",
}

export const TodoComponent: FC<TodoComponentProps> = memo(
  ({
    todo: { _id, content, reminderTime },
    leftIcon,
    handleDelete,
    done,
    drag,
    setDrag,
    handleDone,
    handleTodo,
  }): ReactElement => {
    const todoTime = new Date(reminderTime);
    const overtime = done ? todoTime.getTime() < new Date().getTime() : done;

    const dragStart = ({ target, dataTransfer }: any) => {
      console.log("start:", target);
      setDrag(true);
      target.style.opacity = "0.4";
      //方便存取 localStorage
      localStorage.setItem(DragConstant.DRAG_ELEMENT_ID, target.id);
      localStorage.setItem(DragConstant.DRAG_ELEMENT_STATUS, `${true}`);
      localStorage.setItem(
        DragConstant.DRAG_HEIGHT,
        String(target.offsetHeight)
      );
      //只有在 drop 事件中才能获取到dataTransfer
      dataTransfer.setData("drag-id", target.id);
    };

    // onDragOver 不然onDrop无效
    const onDragOver = useCallback(e => {
      e.preventDefault();
    }, []);

    const onDragEnter = useCallback(e => {
      const { target } = e;
      //阻止冒泡 至关重要
      e.stopPropagation();
      //阻止捕获 没用
      //e.nativeEvent.stopImmediatePropagation();
      //step1,获取todoItem 的top 还是bottom 如果不是不需要操作
      const position = target.getAttribute(DragConstant.DATA_PROPERTY);
      const container = target.parentElement;
      if (
        !position ||
        container.id === localStorage.getItem(DragConstant.DRAG_ELEMENT_ID)
      )
        return;
      //step2,设置todoItem的padding使之看起来向上或向下位移
      const height = localStorage.getItem(DragConstant.DRAG_HEIGHT) || "0";
      const prevH = container.firstChild.offsetHeight;
      target.style["z-index"] = 2;
      // 原先的高度 + 新增的高度 防止容器整体高度增加时，鼠标还在原位置如 下层mask 因为高度发送变化 上面的mask高度达到了鼠标放置位置 使位置上移 造成闪动
      target.style["height"] = `calc(${prevH / 2}px + 0.2rem + ${parseFloat(
        height
      )}px)`;
      container.style[`padding-${position}`] = `calc(0.2rem + ${height}px)`;
    }, []);

    const cancelActive = useCallback((target, position) => {
      target.style["z-index"] = 1;
      target.parentElement.style[`padding-${position}`] = "0.2rem";
      target.style["height"] = `50%`;
    }, []);

    const onDragLeave = useCallback(
      ({ target }) => {
        const position = target.getAttribute(DragConstant.DATA_PROPERTY);
        if (position) {
          cancelActive(target, position);
        }
      },
      [cancelActive]
    );

    const onDrop = useCallback(
      e => {
        e.preventDefault();
        const dragId = e.dataTransfer.getData("drag-id");
        console.log("放下鼠标，完成拖放", e.target, dragId);
        const drag = document.getElementById(dragId);
        if (drag) {
          drag.style["opacity"] = "1";
          setDrag(false);
          const status =
            localStorage.getItem(DragConstant.DRAG_ELEMENT_STATUS) === "true";
          //   if (status) handleTodo(dragId)();
          //   else handleDone(dragId);
          cancelActive(
            e.target,
            e.target.getAttribute(DragConstant.DATA_PROPERTY)
          );
        }
      },
      [setDrag, handleDone, handleTodo, cancelActive]
    );

    const onDragEnd = useCallback(
      e => {
        console.log("拖拽结束");
        if (drag) {
          e.target.style["opacity"] = "1";
          setDrag(false);
          console.log("拖了个寂寞");
        }
      },
      [drag, setDrag]
    );

    return (
      <TodoItem
        id={_id}
        drag={drag}
        draggable={true}
        onDrop={onDrop}
        onDragStart={dragStart}
        onDragEnter={onDragEnter}
        onDragLeave={onDragLeave}
        onDragOver={onDragOver}
        onDragEnd={onDragEnd}
      >
        <TodoItemContent bgc={done ? "#999999dd" : undefined}>
          {leftIcon}
          <Content>
            <span>{content}</span>
            <span
              style={done ? { color: "#eee" } : undefined}
              date-overtime={`${overtime}`}
            >
              {todoTime.toLocaleString()}
            </span>
          </Content>
          <DeleteIcon onClick={handleDelete(_id)} />
        </TodoItemContent>
        <TopMask />
        <BottomMask />
      </TodoItem>
    );
  }
);

const MaskStyle = css`
  position: absolute;
  left: 0;
  height: 50%;
  width: 100%;
  z-index: 1;
`;

const TopMask = styled.div.attrs({
  [`${DragConstant.DATA_PROPERTY}`]: DragConstant.POSITION_TOP,
})`
  ${MaskStyle}
  top: 0;
`;

const BottomMask = styled.div.attrs({
  [DragConstant.DATA_PROPERTY]: DragConstant.POSITION_BOTTOM,
})`
  ${MaskStyle}
  bottom: 0;
`;

const TodoItem = styled.div<{ drag: boolean }>`
  padding: 0.2rem 0;
  transition-property: padding-top, padding-bottom, opacity;
  transition-duration: 0.3s;
  transition-timing-function: linear;
  position: relative;

  &:hover div[data-position] {
    z-index: -1 ${props => (props.drag ? undefined : "!important")};
  }
`;

const TodoItemContent = styled.div<{ bgc?: string }>`
  display: flex;
  align-items: center;
  border-radius: 0.2rem;
  padding: 0.2rem 0.5rem;
  background-color: ${props => props.bgc};

  ${DeleteIcon} {
    opacity: 0;
    transition: opacity 0.3s ease-in;
  }

  &:hover ${DeleteIcon} {
    opacity: 1;
  }
`;

TodoItemContent.defaultProps = {
  bgc: "#FFF",
};

const Content = styled.div`
  display: flex;
  flex-direction: column;
  flex: 1;
  margin: 0 0.5rem;

  & > span:nth-child(2) {
    font-size: 0.8rem;
    color: #666;
  }

  & > span:nth-child(2)[date-overtime="true"] {
    color: #f00;
  }
`;

export default TodoComponent;
